﻿bob.ns.setNs('bob.fn', {

    //v.2
    Overload: function () {

        var self = this;

        var _overloads = [];

        this.add = function (fnCondition, fnOverload) {
            if (!bob.utils.isFunction(fnCondition)) {
                throw new Error('Wrong argument: fnCondition.');
            }
            if (!bob.utils.isFunction(fnOverload)) {
                throw new Error('Wrong argument: fnOverload.');
            }

            _overloads.push({ condition: fnCondition, overload: fnOverload });
        };

        this.call = function () {
            var objThis = this;
            var args = arguments;

            var objOverload = (function () {
                for (var i = 0; i < _overloads.length; i++) {
                    if (_overloads[i].condition.apply(objThis, args)) {
                        return _overloads[i];
                    }
                }

                return null;
            })();

            if (!objOverload) {
                throw new Error('No matching overload found.');
            }

            return objOverload.overload.apply(objThis, args);
        };
    },

    //v.2
    overloadFunction: function (arrFunctionObjects) {

        if (!bob.utils.isArray(arrFunctionObjects)) {
            throw new Error('Wrong argument: arrFunctionObjects.');
        }
        if (!arrFunctionObjects.length) {
            throw new Error('Number of overloads must be more than zero.');
        }

        var overload = new bob.fn.Overload();
        for (var i = 0; i < arrFunctionObjects.length; i++) {
            overload.add(arrFunctionObjects[i].condition, arrFunctionObjects[i].overload);
        }

        return overload.call;
    },

    //fixedObjectFunction - implicitly from _last.

    //v.2
    getArgumentNames: function (func) {
        if (!bob.utils.isFunction(func)) {
            throw new Error('Wrong argument: func.');
        }

        var funStr = func.toString();
        var matches = funStr.slice(funStr.indexOf('(') + 1, funStr.indexOf(')')).match(/([^\s,]+)/g);
        return bob.utils.isArray(matches) ? matches : [];
    },

    //v.2
    namedArgFunction: function (fnOriginal) {
        if (!bob.utils.isFunction(fnOriginal)) {
            throw new Error('Wrong argument: fnOriginal.');
        }

        var argNames = bob.fn.getArgumentNames(fnOriginal);

        var result = function (objArguments) {
            var args = bob.utils.isUndefinedOrNull(objArguments) ? [] :
            bob.collections.extensions.select.call(argNames, function (index, arg) {
                return objArguments[arg];
            });

            return fnOriginal.apply(this, args);
        };
        
        return result;
    }

});
